﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SystemX.Infrastructure;
using SalePoints.Web.Models;
using SystemX.Utility;
using SystemX;
using System.IO;

namespace SalePoints.Models
{
	public class BOSalePoint
	{
		#region factory methods
		public static List<SalePointInfo> LoadData(DataLegendGroup group,SaleChannel channel,out BOMessager msg) {
			msg = new BOMessager();
			var retVal = new List<SalePointInfo>();
			try
			{
				switch (group)
				{
					case DataLegendGroup.Hourly:
						retVal = loadHourlyData(channel);
						break;
					case DataLegendGroup.Daily:
						retVal = loadDailyData(channel);
						break;
					case DataLegendGroup.Monthly:
						retVal = loadMonthlyData(channel);
						break;
				}
			}
			catch (Exception ex) {
				msg.Error<BOSalePoint>(ex, true);
			}
			return retVal;
		}
		public static List<SaleChannel> ChannelList
		{
			get
			{
				return new List<SaleChannel> { 
					SaleChannel.HealthDep,
					SaleChannel.MailOrder,
					SaleChannel.Store,
					SaleChannel.Website
				};
			}
		}
		public static SaleChannel FullChannel {
			get
			{
				return (SaleChannel.Website|SaleChannel.Store|SaleChannel.MailOrder|SaleChannel.HealthDep);
			}
		}
		public static List<DataLegend> GetLegendList(DataLegendGroup group) {
			var retVal = new List<DataLegend>();
			switch (group)
			{
				case DataLegendGroup.Hourly:
					retVal = new List<DataLegend> { 
					DataLegend.HourlyToday,
					DataLegend.HourlyYesterday,
					DataLegend.MonthlyLastYear
					};
					break;
				case DataLegendGroup.Daily:
					retVal = new List<DataLegend> { 
						DataLegend.DailyLastMonth,
						DataLegend.DailyThisMonth,
						DataLegend.DailyLastYearSameMonth
					};
					break;
				case DataLegendGroup.Monthly:
					retVal = new List<DataLegend> { 
						DataLegend.MonthlyThisYear,
						DataLegend.MonthlyLastYear,
						DataLegend.MonthlyPlan
					};
					break;
			}
			return retVal;
		}
		/// <summary>
		/// 统计昨天、上周同期每小时数据.由自动任务执行，数据保存于app_data/cache/SalePoints.Hourly.dateFlag.xml
		/// </summary>
		/// <param name="dateFlag"></param>
		/// <param name="msg"></param>
		public static void StatHourly(DateTime dateFlag,out BOMessager msg){
			msg = new BOMessager();
			var sDate = dateFlag.Date;
			var eDate = dateFlag.Date.AddDays(1);
			var cachedFile = HttpContext.Current.Server.MapPath(string.Format("~/app_data/cache/SalePoints.Hourly.{0}.xml", sDate.ToString("yyyyMMdd")));
			var retVal = new List<SalePointInfo>();
			try
			{
				loadYesterdayAndLastweekData(ref retVal, sDate, eDate,true);
				var xmlCache = AppSettingsHelper.Instance.GetBoolean("SalePoints.Hourly.XMLCache");
				//写xml文件（其实可以不写xml）
				if (xmlCache)
				{
					retVal.ToXMLDoc(cachedFile);
				}
			}
			catch (Exception ex)
			{
				msg.Error<BOSalePoint>(ex, true);
			}
		}
		/// <summary>
		/// 统计当天每小时销售，并缓存与xml和asp.net cache
		/// </summary>
		/// <param name="msg"></param>
		public static void StatHourlyToday(out BOMessager msg) {
			msg = new BOMessager();
			try
			{
				var cacheTime = AppSettingsHelper.Instance.GetDecimal("SalePoints.Hourly.CacheInterval");
				var tempData=new List<SalePointInfo>();
				loadTodayData(ref tempData, DateTime.Now.Date, DateTime.Now, DateTime.Now.AddMinutes(Convert.ToDouble(cacheTime)),true);
				tempData = null;
			}
			catch (Exception ex) {
				msg.Error<BOSalePoint>(ex, true);
			}
		}
		#endregion

		#region helper methods
		private static List<SalePointInfo> loadMonthlyData(SaleChannel channel)
		{
			throw new NotImplementedException();
		}

		private static List<SalePointInfo> loadDailyData(SaleChannel channel)
		{
			throw new NotImplementedException();
		}

		private static List<SalePointInfo> loadHourlyData(SaleChannel channel)
		{
			//Note:parameter channel is currently not used.
			var sDate=DateTime.Now.Date;
			var eDate=DateTime.Now;

			var cacheTime = AppSettingsHelper.Instance.GetDecimal("SalePoints.Hourly.Interval");
			cacheTime = cacheTime / 2;

			var isAutoTask = AppSettingsHelper.Instance.GetBoolean("SalePoints.Hourly.AutoTask");
			if (isAutoTask) {
				cacheTime = AppSettingsHelper.Instance.GetDecimal("SalePoints.Hourly.CacheInterval");
			}
			//record start time
			if (SystemX.Web.Utils.IsWebDebug) {
				Logger<BOSalePoint>.Current.Info(string.Format("----开始按时统计{0}---\r\n",DateTime.Now));
			}
			var retVal = new List<SalePointInfo>();
			//Today
			loadTodayData(ref retVal, sDate, eDate, eDate.AddMinutes(Convert.ToDouble(cacheTime)),false);

			//Yesterday&lastweek's data.From cache or xml file			
			loadYesterdayAndLastweekData(ref retVal, sDate,eDate,false);

			//record end time
            if (SystemX.Web.Utils.IsWebDebug)
			{
				Logger<BOSalePoint>.Current.Info(string.Format("----结束按时统计{0}---\r\n", DateTime.Now));
			}
			return retVal;
		}
		/// <summary>
		/// 统计当天每小时数据，并至于缓存
		/// </summary>
		/// <param name="retVal"></param>
		/// <param name="sDate"></param>
		/// <param name="eDate"></param>
		/// <param name="cacheExpired"></param>
		private static void loadTodayData(ref List<SalePointInfo> retVal,DateTime sDate,DateTime eDate,DateTime cacheExpired,bool ignoreCache) {
			var cachedKey = string.Format("BOSalePoint.Hourly.Now.{0}", sDate.ToString("yyyyMMdd"));
			var tempData = CacheServices.Get(cachedKey) as List<SalePointInfo>;
			if (ignoreCache) { tempData = null; }
			if (tempData == null)
			{
				//from data base
				tempData = new List<SalePointInfo>();
				//website
				var sp = SalePoints.M18RssModels.SPs.HourlyOrderM18(sDate, eDate);
				tempData.AddRange(loadData(sp, SaleChannel.Website, DataLegend.HourlyToday, eDate));
				//mailorder
				sp = SalePoints.ClopRssModels.SPs.HourlyOrder(sDate, eDate);
				tempData.AddRange(loadData(sp, SaleChannel.MailOrder, DataLegend.HourlyToday, eDate));
				//store
				sp = SalePoints.ShopModels.SPs.HourlyOrderStore(sDate, eDate);
				tempData.AddRange(loadData(sp, SaleChannel.Store, DataLegend.HourlyToday, eDate));

				fullfillData(ref tempData, eDate, DataLegendGroup.Hourly, DataLegend.HourlyToday);
				//record end time
				if (SystemX.Web.Utils.IsWebDebug)
				{
					Logger<BOSalePoint>.Current.Info(string.Format("----结束按时统计-当天{0}---\r\n", DateTime.Now));
				}
				//cache.(No need to cache in xml file,because we have so few data here)
				CacheServices.Add(cachedKey, tempData, cacheExpired);
			};
			retVal.AddRange(tempData);
		}
		private static void loadYesterdayAndLastweekData(ref List<SalePointInfo> retVal, DateTime sDate,DateTime eDate,bool ignoreCache)
		{
			var cachedKey = string.Format("BOSalePoint.Hourly.{0}",sDate.ToString("yyyyMMdd"));
			var cachedFile = HttpContext.Current.Server.MapPath(string.Format("~/app_data/cache/SalePoints.Hourly.{0}.xml", sDate.ToString("yyyyMMdd")));
			var tempData = CacheServices.Get(cachedKey) as List<SalePointInfo>;
			//自动任务每次都从数据库统计
			if (ignoreCache)
			{
				tempData = null;
			}
			if (tempData == null)
			{
				if (File.Exists(cachedFile) && (!ignoreCache))
				{
					tempData = XmlUtil.DeserializeFromFile<List<SalePointInfo>>(cachedFile);
				}
				else
				{
					tempData = new List<SalePointInfo>();
					//fetch from database
					//Yesterday
					var sp = SalePoints.M18RssModels.SPs.HourlyOrderM18(sDate.AddDays(-1), eDate.AddDays(-1));
					tempData.AddRange(loadData(sp, SaleChannel.Website, DataLegend.HourlyYesterday, eDate.AddDays(-1)));
					//mailorder
					sp = SalePoints.ClopRssModels.SPs.HourlyOrder(sDate.AddDays(-1), eDate.AddDays(-1));
					retVal.AddRange(loadData(sp, SaleChannel.MailOrder, DataLegend.HourlyYesterday, eDate.AddDays(-1)));
					//store
					sp = SalePoints.ShopModels.SPs.HourlyOrderStore(sDate.AddDays(-1), eDate.AddDays(-1));
					tempData.AddRange(loadData(sp, SaleChannel.Store, DataLegend.HourlyYesterday, eDate.AddDays(-1)));

					fullfillData(ref tempData, eDate.AddDays(-1), DataLegendGroup.Hourly, DataLegend.HourlyYesterday);

					//Last week
					sp = SalePoints.M18RssModels.SPs.HourlyOrderM18(sDate.AddDays(-7), eDate.AddDays(-7));
					tempData.AddRange(loadData(sp, SaleChannel.Website, DataLegend.HourlyLastWeekSameDay, eDate.AddDays(-7)));
					//mailorder
					sp = SalePoints.ClopRssModels.SPs.HourlyOrder(sDate.AddDays(-7), eDate.AddDays(-7));
					tempData.AddRange(loadData(sp, SaleChannel.MailOrder, DataLegend.HourlyLastWeekSameDay, eDate.AddDays(-7)));
					//store
					sp = SalePoints.ShopModels.SPs.HourlyOrderStore(sDate.AddDays(-7), eDate.AddDays(-7));
					tempData.AddRange(loadData(sp, SaleChannel.Store, DataLegend.HourlyLastWeekSameDay, eDate.AddDays(-7)));

					fullfillData(ref tempData, eDate.AddDays(-7), DataLegendGroup.Hourly, DataLegend.HourlyLastWeekSameDay);

					//record end time
                    if (SystemX.Web.Utils.IsWebDebug)
					{
						Logger<BOSalePoint>.Current.Info(string.Format("----结束按时统计-昨天上周{0}---\r\n", DateTime.Now));
					}
				}
				CacheServices.Add(cachedKey, tempData, sDate.AddDays(1));
			};
			retVal.AddRange(tempData);
		}
		private static List<SalePointInfo> loadData(SubSonic.StoredProcedure sp,SaleChannel channel,DataLegend legend,DateTime timeFlag) {
			var retVal = new List<SalePointInfo>();
			sp.CommandTimeout = 0;
			try
			{
				retVal = sp.ExecuteTypedList<SalePointInfo>();
				var key = new SalePointKey
				{
					Channel = channel,
					Legend = legend,
					TimeFlag = timeFlag
				};
				retVal.ForEach(x =>
				{
					if (x.Flag == SalePointFlag.HEALTH)
					{
						key = new SalePointKey
						{
							Channel = SaleChannel.HealthDep,
							Legend = legend,
							TimeFlag = timeFlag
						};
					}
					else if (x.Flag == SalePointFlag.MAILORDER)
					{
						key = new SalePointKey
						{
							Channel = SaleChannel.MailOrder,
							Legend = legend,
							TimeFlag = timeFlag
						};
					}
					x.Key = key;
				});
			}
			catch (Exception ex) {
				Logger<BOSalePoint>.Current.Error(ex.Message, ex);
			}
			return retVal;
		}

		private static void fullfillData(ref List<SalePointInfo> retVal,DateTime timeFlag,DataLegendGroup group,DataLegend legend)
		{
			var upperbound = 24;
			switch (group)
			{
				case DataLegendGroup.Hourly:
					upperbound = 24;
					break;
				case DataLegendGroup.Daily:
					upperbound = DateTime.DaysInMonth(timeFlag.Year, timeFlag.Month);
					break;
				case DataLegendGroup.Monthly:
					upperbound = 12;
					break;
			}

			var tempItem = default(SalePointInfo);
			var key=default(SalePointKey);

			foreach(var x in ChannelList){
				key = new SalePointKey
				{
					Channel = x,
					Legend =legend,
					TimeFlag = timeFlag
				};

				for (int i = 0; i < upperbound; i++)
				{
					tempItem = retVal.SingleOrDefault(obj => obj.Key.Equals(key) && obj.Point == i);
					if (tempItem == null)
					{
						retVal.Add(new SalePointInfo
						{
							Amount = 0,
							Flag = x.ToString(),
							Key = key,
							Point = i
						});
					}
				}//endof for	
			}//endof foreach
		}//endof fullfillHourlyData
		#endregion
	}
}
